/*
 * @Date: 2019-12-2
 * @Author: xuechengwu <xuechengwu@erayt.com>
 * @Description: 画线层
 */
import BaseLayer from './BaseLayer';
import Layer from '../core/Layer';
import Circle from '../base/Circle';
import Color from '../core/Color';
import Line from '../base/Line';
import Point from '../core/Point';
import Event from '../event/Event';
import Text from '../base/Text';
import OChart from '../core/OChart';

let uuid = 1;
function UUID() {
  return uuid++;
}
/**
 * 数据线类型
 * {
 *   point1: {
 *     date: 时间戳
 *     price: 价格
 *   },
 *   point2: {
 *     date: 时间戳
 *     price: 价格
 *   },
 *   type: 0, 1, 2//0: 线段，1: 趋势线， 2: 黄金分割线， 3: 自定义分割线， 4、上江恩角度线，5： 下江恩角度线
 *   rate: [], 分割线比例数组
 * }
 * @type {*|string[]|string|Array|number}
 */
export default class DrawLayer extends BaseLayer {
  constructor(canvas, options) {
    super(canvas);
    this.width = options.width;
    this.height = options.height;
    this.xStep = options.xStep || 0;
    this.yStep = options.yStep || 0;
    this.start = options.start || 0;
    this.end = options.end || 0;
    this.max = options.max || 0;
    this.min = options.min || 0;
    this.xAxis = options.xAxis || []; // x轴坐标系
    this.lines = options.lines || [];
    this.onLineMove = options.onLineMove;
    this.onLineMoved = options.onLineMoved;
    this.version = OChart.version;
    this.selectedLine = null;
  }

  /**
   * 查找某个日期的下标
   * @param date
   * @param data
   * @returns {number|*}
   */
  findIndex(date, data) {
    if (parseInt(date) > parseInt(data[data.length - 1])) {
      let shift = Math.round(
        (parseInt(date) - parseInt(data[data.length - 1]))
        / (parseInt(data[data.length - 1]) - parseInt(data[data.length - 2]))
      ) + data.length;
      return shift;
    }
    let cur = parseInt(date);
    for(let i = 1; i < data.length; i++) {
      if (cur >= parseInt(data[i - 1]) && cur <= parseInt(data[i])) {
        return i;
      }
    }
  }

  /**
   * 清除选中线条
   */
  clearSelected() {
    for(let i = 0; i < this.lines.length; i++) {
      this.lines[i].isSelected = false;
    }
  }

  /**
   * 渲染
   */
  make() {
    if (this.locked) {
      return;
    }
    this.clearEventListener();
    this.childs.splice(0, this.childs.length);
    for (let i = 0; i < this.lines.length; i++) {
      const shift1 = this.findIndex(this.lines[i].point1.date, this.xAxis);
      const x1 = (shift1 - this.start) * this.xStep;
      const shift2 = this.findIndex(this.lines[i].point2.date, this.xAxis);
      const x2 = (shift2 - this.start) * this.xStep;

      if (this.lines[i].type === 1) {
        // 直线
        const uuid = this.lines[i].uuid !== undefined ? this.lines[i].uuid : UUID();
        const straight = new StraightLayer(this.canvas, {
          uuid: uuid,
          width: this.width,
          height: this.height,
          point1: new Point(x1, (this.lines[i].point1.price - this.min) * this.yStep),
          point2: new Point(x2, (this.lines[i].point2.price - this.min) * this.yStep),
          color: this.lines[i].color,
          version: this.version,
          onLineMove: (option) => {
            const shift1 = Math.round(option.point1.x / this.xStep + this.start);
            const shift2 = Math.round(option.point2.x / this.xStep + this.start);
            const y1 = option.point1.y / this.yStep + this.min;
            const y2 = option.point2.y / this.yStep + this.min;
            let x1 = 0;
            let x2 = 0;
            const xTimeDelta = parseInt(this.xAxis[this.xAxis.length - 1]) - parseInt(this.xAxis[this.xAxis.length - 2]);
            if (shift1 > this.xAxis.length) {
              x1 = xTimeDelta * (shift1 - this.xAxis.length) + parseInt(this.xAxis[this.xAxis.length - 1]);
            } else if (shift1 < 0) {
              x1 = parseInt(this.xAxis[0]) + xTimeDelta * shift1;
            } else {
              x1 = this.xAxis[shift1];
            }
            if (shift2 > this.xAxis.length) {
              x2 = xTimeDelta * (shift2 - this.xAxis.length) + parseInt(this.xAxis[this.xAxis.length - 1]);
            } else if(shift2 < 0) {
              x2 = parseInt(this.xAxis[0]) + xTimeDelta * shift2;
            } else {
              x2 = this.xAxis[shift2];
            }
            const index = this.lines.findIndex(item => item.uuid === option.line.uuid);
            if (index >= 0) {
              this.lines[index].point1.date = x1;
              this.lines[index].point1.price = y1;
              this.lines[index].point2.date = x2;
              this.lines[index].point2.price = y2;
            }
            this.onLineMove && this.onLineMove(option.line);
          },
          onLineMoved: (line) => {
            this.onLineMoved && this.onLineMoved(line);
          }
        });
        straight.addEventListener(OChart.version === OChart.VERSION.PC ? Event.EVENT_CLICK : Event.EVENT_TAP, (e) => {
            console.log('uuid', this.onSelected);
          const index = this.lines.findIndex(item => item.uuid === uuid);
          this.clearSelected();
          this.lines[index].isSelected = true;
          this.make();
          this.canvas.paint();
          this.onSelected && this.onSelected(uuid);
        });
        this.addChild(straight);
        if (this.lines[i].isSelected) {
          straight.setSelected(true);
          this.selectedLine = uuid;
        } else {
          straight.setSelected(false);
        }
        this.lines[i].uuid = uuid;
      } else if(this.lines[i].type === 0) {
        // 线段
        const uuid = this.lines[i].uuid !== undefined ? this.lines[i].uuid : UUID();
        const segment = new SegmentLayer(this.canvas, {
          uuid: uuid,
          width: this.width,
          height: this.height,
          color: this.lines[i].color,
          point1: new Point(x1, (this.lines[i].point1.price - this.min) * this.yStep),
          point2: new Point(x2, (this.lines[i].point2.price - this.min) * this.yStep),
          version: this.version,
          onLineMove: (option) => {
            const shift1 = Math.round(option.point1.x / this.xStep + this.start);
            const shift2 = Math.round(option.point2.x / this.xStep + this.start);
            const y1 = (option.point1.y / this.yStep + this.min);
            const y2 = (option.point2.y / this.yStep + this.min);
            let x1 = 0;
            let x2 = 0;
            const xTimeDelta = parseInt(this.xAxis[this.xAxis.length - 1]) - parseInt(this.xAxis[this.xAxis.length - 2]);
            if (shift1 > this.xAxis.length) {
              x1 = xTimeDelta * (shift1 - this.xAxis.length) + parseInt(this.xAxis[this.xAxis.length - 1]);
            } else if (shift1 < 0) {
              x1 = parseInt(this.xAxis[0]) + xTimeDelta * shift1;
            } else {
              x1 = this.xAxis[shift1];
            }
            if (shift2 > this.xAxis.length) {
              x2 = xTimeDelta * (shift2 - this.xAxis.length) + parseInt(this.xAxis[this.xAxis.length - 1]);
            } else if(shift2 < 0) {
              x2 = parseInt(this.xAxis[0]) + xTimeDelta * shift2;
            } else {
              x2 = this.xAxis[shift2];
            }
            const index = this.lines.findIndex(item => item.uuid === option.line.uuid);
            if (index >= 0) {
              this.lines[index].point1.date = x1;
              this.lines[index].point1.price = y1;
              this.lines[index].point2.date = x2;
              this.lines[index].point2.price = y2;
            }
            this.onLineMove && this.onLineMove(option.line);
          },
          onLineMoved: (line) => {
            this.onLineMoved && this.onLineMoved(line);
          }
        });
        segment.addEventListener(OChart.version === OChart.VERSION.PC ? Event.EVENT_CLICK : Event.EVENT_TAP, (e) => {
          const index = this.lines.findIndex(item => item.uuid === uuid);
          this.clearSelected();
          this.lines[index].isSelected = true;
          this.make();
          this.canvas.paint();
          this.onSelected && this.onSelected(uuid);
        });
        this.addChild(segment);
        if (this.lines[i].isSelected) {
          segment.setSelected(true);
          this.selectedLine = uuid;
        } else {
          segment.setSelected(false);
        }
        this.lines[i].uuid = uuid;
      } else if(this.lines[i].type === 2) {
        const uuid = this.lines[i].uuid !== undefined ? this.lines[i].uuid : UUID();
        const rule = new RuleLayer(this.canvas, {
          uuid: uuid,
          width: this.width,
          height: this.height,
          mesures: this.lines[i].rules || [0, 23.6, 38.2, 50, 61.8, 80.9, 100],
          point1: new Point(x1, (this.lines[i].point1.price - this.min) * this.yStep),
          point2: new Point(x2, (this.lines[i].point2.price - this.min) * this.yStep),
          version: this.version,
          color: this.lines[i].color,
          onLineMove: (option) => {
            const shift1 = Math.round(option.point1.x / this.xStep + this.start);
            const shift2 = Math.round(option.point2.x / this.xStep + this.start);
            const y1 = (option.point1.y / this.yStep + this.min);
            const y2 = (option.point2.y / this.yStep + this.min);
            let x1 = 0;
            let x2 = 0;
            const xTimeDelta = parseInt(this.xAxis[this.xAxis.length - 1]) - parseInt(this.xAxis[this.xAxis.length - 2]);
            if (shift1 > this.xAxis.length) {
              x1 = xTimeDelta * (shift1 - this.xAxis.length) + parseInt(this.xAxis[this.xAxis.length - 1]);
            } else if (shift1 < 0) {
              x1 = parseInt(this.xAxis[0]) + xTimeDelta * shift1;
            } else {
              x1 = this.xAxis[shift1];
            }
            if (shift2 > this.xAxis.length) {
              x2 = xTimeDelta * (shift2 - this.xAxis.length) + parseInt(this.xAxis[this.xAxis.length - 1]);
            } else if(shift2 < 0) {
              x2 = parseInt(this.xAxis[0]) + xTimeDelta * shift2;
            } else {
              x2 = this.xAxis[shift2];
            }
            const index = this.lines.findIndex(item => item.uuid === option.line.uuid);
            if (index >= 0) {
              this.lines[index].point1.date = x1;
              this.lines[index].point1.price = y1;
              this.lines[index].point2.date = x2;
              this.lines[index].point2.price = y2;
            }
            this.onLineMove && this.onLineMove(option.line);
          },
          onLineMoved: (line) => {
            this.onLineMoved && this.onLineMoved(line);
          }
        });
        rule.addEventListener(Event.EVENT_CLICK, (e) => {
          const index = this.lines.findIndex(item => item.uuid === uuid);
          this.clearSelected();
          this.lines[index].isSelected = true;
          this.make();
          this.canvas.paint();
          this.onSelected && this.onSelected(uuid);
        });
        this.addChild(rule);
        if (this.lines[i].isSelected) {
          rule.setSelected(true);
          this.selectedLine = uuid;
        } else {
          rule.setSelected(false);
        }
        this.lines[i].uuid = uuid;
      } else if (this.lines[i].type === 3) {
          const uuid = this.lines[i].uuid !== undefined ? this.lines[i].uuid : UUID();
          const topGannFanLayer = new TopGannFanLayer(this.canvas, {
              uuid: uuid,
              width: this.width,
              height: this.height,
              point1: new Point(x1, (this.lines[i].point1.price - this.min) * this.yStep),
              color: this.lines[i].color,
              onLineMove: (option) => {
                  const shift1 = Math.round(option.point.x / this.xStep + this.start);
                  const y1 = (option.point.y / this.yStep + this.min);
                  let x1 = 0;
                  const xTimeDelta = parseInt(this.xAxis[this.xAxis.length - 1]) - parseInt(this.xAxis[this.xAxis.length - 2]);
                  if (shift1 > this.xAxis.length) {
                      x1 = xTimeDelta * (shift1 - this.xAxis.length) + parseInt(this.xAxis[this.xAxis.length - 1]);
                  } else if (shift1 < 0) {
                      x1 = parseInt(this.xAxis[0]) + xTimeDelta * shift1;
                  } else {
                      x1 = this.xAxis[shift1];
                  }
                  const index = this.lines.findIndex(item => item.uuid === option.line.uuid);
                  console.log(index, x1, y1);
                  if (index >= 0) {
                      this.lines[index].point1.date = x1;
                      this.lines[index].point1.price = y1;
                  }
                  this.onLineMove && this.onLineMove(option.line);
              },
              onLineMoved: (line) => {
                  this.onLineMoved && this.onLineMoved(line);
              }
          });
          topGannFanLayer.addEventListener(OChart.version === OChart.VERSION.PC ? Event.EVENT_CLICK : Event.EVENT_TAP, (e) => {
              const index = this.lines.findIndex(item => item.uuid === uuid);
              this.clearSelected();
              this.lines[index].isSelected = true;
              this.make();
              this.canvas.paint();
              this.onSelected && this.onSelected(uuid);
          });
          this.addChild(topGannFanLayer);
          if (this.lines[i].isSelected) {
              topGannFanLayer.setSelected(true);
              this.selectedLine = uuid;
          } else {
              topGannFanLayer.setSelected(false);
          }
          this.lines[i].uuid = uuid;
      } else if (this.lines[i].type === 4) {
          const uuid = this.lines[i].uuid !== undefined ? this.lines[i].uuid : UUID();
          const bottomGannFanLayer = new BottomGannFanLayer(this.canvas, {
              uuid: uuid,
              width: this.width,
              height: this.height,
              point1: new Point(x1, (this.lines[i].point1.price - this.min) * this.yStep),
              color: this.lines[i].color,
              onLineMove: (option) => {
                  const shift1 = Math.round(option.point.x / this.xStep + this.start);
                  const y1 = (option.point.y / this.yStep + this.min);
                  let x1 = 0;
                  const xTimeDelta = parseInt(this.xAxis[this.xAxis.length - 1]) - parseInt(this.xAxis[this.xAxis.length - 2]);
                  if (shift1 > this.xAxis.length) {
                      x1 = xTimeDelta * (shift1 - this.xAxis.length) + parseInt(this.xAxis[this.xAxis.length - 1]);
                  } else if (shift1 < 0) {
                      x1 = parseInt(this.xAxis[0]) + xTimeDelta * shift1;
                  } else {
                      x1 = this.xAxis[shift1];
                  }
                  const index = this.lines.findIndex(item => item.uuid === option.line.uuid);
                  console.log(index, x1, y1);
                  if (index >= 0) {
                      this.lines[index].point1.date = x1;
                      this.lines[index].point1.price = y1;
                  }
                  this.onLineMove && this.onLineMove(option.line);
              },
              onLineMoved: (line) => {
                  this.onLineMoved && this.onLineMoved(line);
              }
          });
          bottomGannFanLayer.addEventListener(OChart.version === OChart.VERSION.PC ? Event.EVENT_CLICK : Event.EVENT_TAP, (e) => {
              const index = this.lines.findIndex(item => item.uuid === uuid);
              this.clearSelected();
              this.lines[index].isSelected = true;
              this.make();
              this.canvas.paint();
              this.onSelected && this.onSelected(uuid);
          });
          this.addChild(bottomGannFanLayer);
          if (this.lines[i].isSelected) {
              bottomGannFanLayer.setSelected(true);
              this.selectedLine = uuid;
          } else {
              bottomGannFanLayer.setSelected(false);
          }
          this.lines[i].uuid = uuid;
      }
    }
    this.addEventListener(OChart.version === OChart.VERSION.PC ? Event.EVENT_MOUSE_UP : Event.EVENT_TOUCH_END, (e) => {
        this.onLineMoved && this.onLineMoved();
    })
  }
  containsPoint (point) {
    return point.x >= this.position.x
      && point.x <= this.position.x + this.width
      && point.y >= this.position.y
      && point.y <= this.position.y + this.height;
  }
}

class BottomGannFanLayer extends Layer {
    constructor(canvas, option) {
        super(canvas);
        this.width = option.width;
        this.height = option.height;
        this.uuid = option.uuid;
        this.point1 = option.point1;
        this.onLineMove = option.onLineMove; // 线条移动中
        this.onLineMoved = option.onLineMoved; // 线条移动完成
        this.onLineSelected = option.onLineSelected; // 线条选中
        this.hasChange = false;
        this.color = option.color || '#333333';
        this.circle1 = new Circle(this.canvas, 10);
        this.circle2 = new Circle(this.canvas, 10);
        this.circle1.setPosition(this.point1.x + this.position.x, this.point1.y + this.position.y);
        this.circle1.setColor(new Color(this.color));
        this.circle2.setColor(new Color(this.color));
        let targetPoint = new Point(0, 0);
        if (this.width - this.circle1.position.x > this.circle1.position.y - this.position.y) {
            targetPoint.y = this.position.y;
            targetPoint.x = this.circle1.position.y - this.position.y + this.circle1.position.x;
        } else {
            targetPoint.x = this.width;
            targetPoint.y = this.circle1.position.y - (this.width - this.circle1.position.x);
        }
        this.circle2.setPosition(targetPoint.x, targetPoint.y);
        this.centerLine = new Line(this.canvas, {
            from: this.circle1.position,
            to: this.circle2.position
        });
        this.centerLine.setColor(new Color(this.color));
        // line1 1: 8
        let line1Point = new Point(0, 0);
        if (this.circle1.position.y - (this.width - this.circle1.position.x) / 8 < this.position.y) {
            line1Point.y = this.position.y;
            line1Point.x = (this.circle1.position.y - this.position.y) * 8 + this.circle1.position.x;
        } else {
            line1Point.x = this.width;
            line1Point.y = this.circle1.position.y - (this.width - this.circle1.position.x) / 8;
        }
        this.line1 = new Line(this.canvas, {
            from: this.circle1.position,
            to: line1Point
        });
        this.line1.setColor(new Color(this.color));
        this.addChild(this.line1);
        // line2 2: 8
        let line2Point = new Point(0, 0);
        if (this.circle1.position.y - (this.width - this.circle1.position.x) / 4 < this.position.y) {
            line2Point.y = this.position.y;
            line2Point.x = (this.circle1.position.y - this.position.y) * 4 + this.circle1.position.x;
        } else {
            line2Point.x = this.width;
            line2Point.y = this.circle1.position.y - (this.width - this.circle1.position.x) / 4;
        }
        this.line2 = new Line(this.canvas, {
            from: this.circle1.position,
            to: line2Point
        });
        this.line2.setColor(new Color(this.color));
        this.addChild(this.line2);
        // line3 3: 8
        let line3Point = new Point(0, 0);
        if (this.circle1.position.y - (this.width - this.circle1.position.x) * 3 / 8 < this.position.y) {
            line3Point.y = this.position.y;
            line3Point.x = (this.circle1.position.y - this.position.y) * 8 / 3 + this.circle1.position.x;
        } else {
            line3Point.x = this.width;
            line3Point.y = this.circle1.position.y - (this.width - this.circle1.position.x) / 8 * 3;
        }
        this.line3 = new Line(this.canvas, {
            from: this.circle1.position,
            to: line3Point
        });
        this.line3.setColor(new Color(this.color));
        this.addChild(this.line3);
        // line4
        let line4Point = new Point(0, 0);
        if ((this.circle1.position.y - this.position.y) * 3 / 8 + this.circle1.position.x > this.width) {
            line4Point.x = this.width;
            line4Point.y = this.circle1.position.y - (this.width - this.circle1.position.x) * 8 / 3;
        } else {
            line4Point.y = this.position.y;
            line4Point.x = (this.circle1.position.y - this.position.y) * 3 / 8 + this.circle1.position.x;
        }
        this.line4 = new Line(this.canvas, {
            from: this.circle1.position,
            to: line4Point
        });
        this.line4.setColor(new Color(this.color));
        this.addChild(this.line4);
        // line5
        let line5Point = new Point(0, 0);
        if ((this.circle1.position.y - this.position.y) / 4 + this.circle1.position.x > this.width) {
            line5Point.x = this.width;
            line5Point.y = this.circle1.position.y - (this.width - this.circle1.position.x) * 4;
        } else {
            line5Point.y = this.position.y;
            line5Point.x = (this.circle1.position.y - this.position.y) / 4 + this.circle1.position.x;
        }
        this.line5 = new Line(this.canvas, {
            from: this.circle1.position,
            to: line5Point
        });
        this.line5.setColor(new Color(this.color));
        this.addChild(this.line5);
        // line6
        let line6Point = new Point(0, 0);
        if ((this.circle1.position.y - this.position.y) / 8 + this.circle1.position.x > this.width) {
            line6Point.x = this.width;
            line6Point.y = this.circle1.position.y - (this.width - this.circle1.position.x) * 8;
        } else {
            line6Point.y = this.position.y;
            line6Point.x = (this.circle1.position.y - this.position.y) / 8 + this.circle1.position.x;
        }
        this.line6 = new Line(this.canvas, {
            from: this.circle1.position,
            to: line6Point
        });
        this.line6.setColor(new Color(this.color));
        this.addChild(this.line6);
        this.addChild(this.centerLine, this.circle1, this.circle2);
        this.circle1.addEventListener(OChart.version === OChart.VERSION.PC ? Event.EVENT_MOUSE_MOVE : Event.EVENT_TOUCH_MOVE, (e) => {
            const deltaX = e.curPoint.x - e.eventPoint.x;
            const deltaY = e.curPoint.y - e.eventPoint.y;
            this.point1.x += deltaX;
            this.point1.y += deltaY;
            this.circle1.setPosition(this.point1.x, this.point1.y);
            let targetPoint = new Point(0, 0);
            if (this.width - this.circle1.position.x > this.circle1.position.y - this.position.y) {
                targetPoint.y = this.position.y;
                targetPoint.x = this.circle1.position.y - this.position.y + this.circle1.position.x;
            } else {
                targetPoint.x = this.width;
                targetPoint.y = this.circle1.position.y - (this.width - this.circle1.position.x);
            }
            this.circle2.setPosition(targetPoint.x, targetPoint.y);
            this.centerLine.setFrom(this.circle1.position);
            this.centerLine.setTo(this.circle2.position);
            // line1 1: 8
            let line1Point = new Point(0, 0);
            if (this.circle1.position.y - (this.width - this.circle1.position.x) / 8 < this.position.y) {
                line1Point.y = this.position.y;
                line1Point.x = (this.circle1.position.y - this.position.y) * 8 + this.circle1.position.x;
            } else {
                line1Point.x = this.width;
                line1Point.y = this.circle1.position.y - (this.width - this.circle1.position.x) / 8;
            }
            this.line1.setFrom(this.circle1.position);
            this.line1.setTo(line1Point);
            // line2 2: 8
            let line2Point = new Point(0, 0);
            if (this.circle1.position.y - (this.width - this.circle1.position.x) / 4 < this.position.y) {
                line2Point.y = this.position.y;
                line2Point.x = (this.circle1.position.y - this.position.y) * 4 + this.circle1.position.x;
            } else {
                line2Point.x = this.width;
                line2Point.y = this.circle1.position.y - (this.width - this.circle1.position.x) / 4;
            }
            this.line2.setFrom(this.circle1.position);
            this.line2.setTo(line2Point);
            // line3 3: 8
            let line3Point = new Point(0, 0);
            if (this.circle1.position.y - (this.width - this.circle1.position.x) * 3 / 8 < this.position.y) {
                line3Point.y = this.position.y;
                line3Point.x = (this.circle1.position.y - this.position.y) * 8 / 3 + this.circle1.position.x;
            } else {
                line3Point.x = this.width;
                line3Point.y = this.circle1.position.y - (this.width - this.circle1.position.x) / 8 * 3;
            }
            this.line3.setFrom(this.circle1.position);
            this.line3.setTo(line3Point);
            // line4
            let line4Point = new Point(0, 0);
            if ((this.circle1.position.y - this.position.y) * 3 / 8 + this.circle1.position.x > this.width) {
                line4Point.x = this.width;
                line4Point.y = this.circle1.position.y - (this.width - this.circle1.position.x) * 8 / 3;
            } else {
                line4Point.y = this.position.y;
                line4Point.x = (this.circle1.position.y - this.position.y) * 3 / 8 + this.circle1.position.x;
            }
            this.line4.setFrom(this.circle1.position);
            this.line4.setTo(line4Point);
            // line5
            let line5Point = new Point(0, 0);
            if ((this.circle1.position.y - this.position.y) / 4 + this.circle1.position.x > this.width) {
                line5Point.x = this.width;
                line5Point.y = this.circle1.position.y - (this.width - this.circle1.position.x) * 4;
            } else {
                line5Point.y = this.position.y;
                line5Point.x = (this.circle1.position.y - this.position.y) / 4 + this.circle1.position.x;
            }
            this.line5.setFrom(this.circle1.position);
            this.line5.setTo(line5Point);
            // line6
            let line6Point = new Point(0, 0);
            if ((this.circle1.position.y - this.position.y) / 8 + this.circle1.position.x > this.width) {
                line6Point.x = this.width;
                line6Point.y = this.circle1.position.y - (this.width - this.circle1.position.x) * 8;
            } else {
                line6Point.y = this.position.y;
                line6Point.x = (this.circle1.position.y - this.position.y) / 8 + this.circle1.position.x;
            }
            this.line6.setFrom(this.circle1.position);
            this.line6.setTo(line6Point);
            this.hasChange = true;
            this.canvas.paint();
            this.onLineMove && this.onLineMove({
                line: this,
                point: this.point1
            });
        });
        this.circle1.addEventListener(OChart.version === OChart.VERSION.PC ? Event.EVENT_MOUSE_UP : Event.EVENT_TOUCH_END, (e) => {
            if (this.hasChange) {
                this.onLineMoved && this.onLineMoved(this);
            }
            this.hasChange = false;
        }) ;
    }

    setSelected(isSelected) {
        this.circle1.visible = isSelected;
        this.circle2.visible = isSelected;
    }

    containsPoint (point) {
        let k = (this.circle1.position.y - this.circle2.position.y) / (this.circle1.position.x - this.circle2.position.x);
        let yDown = k * (point.x - this.circle2.position.x) + this.circle2.position.y - 10;
        let yUp = yDown + 20;
        if ((point.x - this.circle1.position.x) * (point.x - this.circle2.position.x) < 0 && (point.y - yDown) * (point.y - yUp) < 0) {
            return true;
        }
        return false;
    }
}

class TopGannFanLayer extends Layer {
    constructor(canvas, option) {
        super(canvas);
        this.width = option.width;
        this.height = option.height;
        this.uuid = option.uuid;
        this.point1 = option.point1;
        this.onLineMove = option.onLineMove; // 线条移动中
        this.onLineMoved = option.onLineMoved; // 线条移动完成
        this.onLineSelected = option.onLineSelected; // 线条选中
        this.hasChange = false;
        this.color = option.color || '#333333';
        this.circle1 = new Circle(this.canvas, 10);
        this.circle2 = new Circle(this.canvas, 10);
        this.circle1.setPosition(this.point1.x + this.position.x, this.point1.y + this.position.y);
        this.circle1.setColor(new Color(this.color));
        this.circle2.setColor(new Color(this.color));
        let targetPoint = new Point(0, 0);
        if (this.width - this.circle1.position.x > this.height - this.circle1.position.y) {
            targetPoint.y = this.height;
            targetPoint.x = this.height - this.circle1.position.y + this.circle1.position.x;
        } else {
            targetPoint.x = this.width;
            targetPoint.y = this.width - this.circle1.position.x + this.circle1.position.y;
        }
        this.circle2.setPosition(targetPoint.x, targetPoint.y);
        this.centerLine = new Line(this.canvas, {
            from: this.circle1.position,
            to: this.circle2.position
        });
        this.centerLine.setColor(new Color(this.color));
        // line1 1: 8
        let line1Point = new Point(0, 0);
        if ((this.width - this.circle1.position.x) / 8 + this.circle1.position.y > this.height) {
            line1Point.y = this.height;
            line1Point.x = (this.height - this.circle1.position.y) * 8 + this.circle1.position.x;
        } else {
            line1Point.x = this.width;
            line1Point.y = (this.width - this.circle1.position.x) / 8 + this.circle1.position.y;
        }
        this.line1 = new Line(this.canvas, {
            from: this.circle1.position,
            to: line1Point
        });
        this.line1.setColor(new Color(this.color));
        this.addChild(this.line1);
        // line2 2: 8
        let line2Point = new Point(0, 0);
        if ((this.width - this.circle1.position.x) / 4 + this.circle1.position.y > this.height) {
            line2Point.y = this.height;
            line2Point.x = (this.height - this.circle1.position.y) * 4 + this.circle1.position.x;
        } else {
            line2Point.x = this.width;
            line2Point.y = (this.width - this.circle1.position.x) / 4 + this.circle1.position.y;
        }
        this.line2 = new Line(this.canvas, {
            from: this.circle1.position,
            to: line2Point
        });
        this.line2.setColor(new Color(this.color));
        this.addChild(this.line2);
        // line3 3: 8
        let line3Point = new Point(0, 0);
        if ((this.width - this.circle1.position.x) * 3 / 8 + this.circle1.position.y > this.height) {
            line3Point.y = this.height;
            line3Point.x = (this.height - this.circle1.position.y) * 8 / 3 + this.circle1.position.x;
        } else {
            line3Point.x = this.width;
            line3Point.y = (this.width - this.circle1.position.x) / 8 * 3 + this.circle1.position.y;
        }
        this.line3 = new Line(this.canvas, {
            from: this.circle1.position,
            to: line3Point
        });
        this.line3.setColor(new Color(this.color));
        this.addChild(this.line3);
        // line4
        let line4Point = new Point(0, 0);
        if ((this.height - this.circle1.position.y) * 3 / 8 + this.circle1.position.x > this.width) {
            line4Point.x = this.width;
            line4Point.y = (this.width - this.circle1.position.x) * 8 / 3 + this.circle1.position.y;
        } else {
            line4Point.y = this.height;
            line4Point.x = (this.height - this.circle1.position.y) * 3 / 8 + this.circle1.position.x;
        }
        this.line4 = new Line(this.canvas, {
            from: this.circle1.position,
            to: line4Point
        });
        this.line4.setColor(new Color(this.color));
        this.addChild(this.line4);
        // line5
        let line5Point = new Point(0, 0);
        if ((this.height - this.circle1.position.y) / 4 + this.circle1.position.x > this.width) {
            line5Point.x = this.width;
            line5Point.y = (this.width - this.circle1.position.x) * 4 + this.circle1.position.y;
        } else {
            line5Point.y = this.height;
            line5Point.x = (this.height - this.circle1.position.y) / 4 + this.circle1.position.x;
        }
        this.line5 = new Line(this.canvas, {
            from: this.circle1.position,
            to: line5Point
        });
        this.line5.setColor(new Color(this.color));
        this.addChild(this.line5);
        // line6
        let line6Point = new Point(0, 0);
        if ((this.height - this.circle1.position.y) / 8 + this.circle1.position.x > this.width) {
            line6Point.x = this.width;
            line6Point.y = (this.width - this.circle1.position.x) * 8 + this.circle1.position.y;
        } else {
            line6Point.y = this.height;
            line6Point.x = (this.height - this.circle1.position.y) / 8 + this.circle1.position.x;
        }
        this.line6 = new Line(this.canvas, {
            from: this.circle1.position,
            to: line6Point
        });
        this.line6.setColor(new Color(this.color));
        this.addChild(this.line6);
        this.addChild(this.centerLine, this.circle1, this.circle2);
        this.circle1.addEventListener(OChart.version === OChart.VERSION.PC ? Event.EVENT_MOUSE_MOVE : Event.EVENT_TOUCH_MOVE, (e) => {
            const deltaX = e.curPoint.x - e.eventPoint.x;
            const deltaY = e.curPoint.y - e.eventPoint.y;
            this.point1.x += deltaX;
            this.point1.y += deltaY;
            this.circle1.setPosition(this.point1.x, this.point1.y);
            let targetPoint = new Point(0, 0);
            if (this.width - this.circle1.position.x > this.height - this.circle1.position.y) {
                targetPoint.y = this.height;
                targetPoint.x = this.height - this.circle1.position.y + this.circle1.position.x;
            } else {
                targetPoint.x = this.width;
                targetPoint.y + this.width - this.circle1.position.x + this.circle1.position.y;
            }
            this.circle2.setPosition(targetPoint.x, targetPoint.y);
            this.centerLine.setFrom(this.circle1.position);
            this.centerLine.setTo(this.circle2.position);
            // line1 1: 8
            let line1Point = new Point(0, 0);
            if ((this.width - this.circle1.position.x) / 8 + this.circle1.position.y > this.height) {
                line1Point.y = this.height;
                line1Point.x = (this.height - this.circle1.position.y) * 8 + this.circle1.position.x;
            } else {
                line1Point.x = this.width;
                line1Point.y = (this.width - this.circle1.position.x) / 8 + this.circle1.position.y;
            }
            this.line1.setFrom(this.circle1.position);
            this.line1.setTo(line1Point);
            // line2 2: 8
            let line2Point = new Point(0, 0);
            if ((this.width - this.circle1.position.x) / 4 + this.circle1.position.y > this.height) {
                line2Point.y = this.height;
                line2Point.x = (this.height - this.circle1.position.y) * 4 + this.circle1.position.x;
            } else {
                line2Point.x = this.width;
                line2Point.y = (this.width - this.circle1.position.x) / 4 + this.circle1.position.y;
            }
            this.line2.setFrom(this.circle1.position);
            this.line2.setTo(line2Point);
            // line3 3: 8
            let line3Point = new Point(0, 0);
            if ((this.width - this.circle1.position.x) * 3 / 8 + this.circle1.position.y > this.height) {
                line3Point.y = this.height;
                line3Point.x = (this.height - this.circle1.position.y) * 8 / 3 + this.circle1.position.x;
            } else {
                line3Point.x = this.width;
                line3Point.y = (this.width - this.circle1.position.x) / 8 * 3 + this.circle1.position.y;
            }
            this.line3.setFrom(this.circle1.position);
            this.line3.setTo(line3Point);
            // line4
            let line4Point = new Point(0, 0);
            if ((this.height - this.circle1.position.y) * 3 / 8 + this.circle1.position.x > this.width) {
                line4Point.x = this.width;
                line4Point.y = (this.width - this.circle1.position.x) * 8 / 3 + this.circle1.position.y;
            } else {
                line4Point.y = this.height;
                line4Point.x = (this.height - this.circle1.position.y) * 3 / 8 + this.circle1.position.x;
            }
            this.line4.setFrom(this.circle1.position);
            this.line4.setTo(line4Point);
            // line5
            let line5Point = new Point(0, 0);
            if ((this.height - this.circle1.position.y) / 4 + this.circle1.position.x > this.width) {
                line5Point.x = this.width;
                line5Point.y = (this.width - this.circle1.position.x) * 4 + this.circle1.position.y;
            } else {
                line5Point.y = this.height;
                line5Point.x = (this.height - this.circle1.position.y) / 4 + this.circle1.position.x;
            }
            this.line5.setFrom(this.circle1.position);
            this.line5.setTo(line5Point);
            // line6
            let line6Point = new Point(0, 0);
            if ((this.height - this.circle1.position.y) / 8 + this.circle1.position.x > this.width) {
                line6Point.x = this.width;
                line6Point.y = (this.width - this.circle1.position.x) * 8 + this.circle1.position.y;
            } else {
                line6Point.y = this.height;
                line6Point.x = (this.height - this.circle1.position.y) / 8 + this.circle1.position.x;
            }
            this.line6.setFrom(this.circle1.position);
            this.line6.setTo(line6Point);
            this.hasChange = true;
            this.canvas.paint();
            this.onLineMove && this.onLineMove({
                line: this,
                point: this.point1
            });
        });
        this.circle1.addEventListener(OChart.version === OChart.VERSION.PC ? Event.EVENT_MOUSE_UP : Event.EVENT_TOUCH_END, (e) => {
            if (this.hasChange) {
                this.onLineMoved && this.onLineMoved(this);
            }
            this.hasChange = false;
        }) ;
    }

    setSelected(isSelected) {
        this.circle1.visible = isSelected;
        this.circle2.visible = isSelected;
    }

    containsPoint (point) {
        let k = (this.circle1.position.y - this.circle2.position.y) / (this.circle1.position.x - this.circle2.position.x);
        let yDown = k * (point.x - this.circle2.position.x) + this.circle2.position.y - 10;
        let yUp = yDown + 20;
        if ((point.x - this.circle1.position.x) * (point.x - this.circle2.position.x) < 0 && (point.y - yDown) * (point.y - yUp) < 0) {
            return true;
        }
        return false;
    }
}

/**
 * 线段
 */
class SegmentLayer extends Layer {
  constructor(canvas, option) {
    super(canvas);
    this.width = option.width;
    this.height = option.height;
    this.uuid = option.uuid;
    this.point1 = option.point1;
    this.point2 = option.point2;
    this.version = option.version || OChart.VERSION.PC;
    this.onLineMove = option.onLineMove;         // 线条移动中
    this.onLineMoved = option.onLineMoved;       // 线条移动完成
    this.onLineSelected = option.onLineSelected; // 线条选中
    this.hasChange = false;
    this.color = option.color || '#333333';
    this.circle1 = new Circle(this.canvas, 10);
    this.circle2 = new Circle(this.canvas, 10);
    this.circle3 = new Circle(this.canvas, 10);
    this.circle1.setPosition(this.point1.x + this.position.x, this.point1.y + this.position.y);
    this.circle2.setPosition(this.point2.x + this.position.x, this.point2.y + this.position.y);
    this.circle3.setPosition(
      (this.point1.x + this.point2.x) / 2 + this.position.x,
      (this.point1.y + this.point2.y) / 2 + this.position.y
    );
    this.circle1.setColor(new Color(this.color));
    this.circle2.setColor(new Color(this.color));
    this.circle3.setColor(new Color(this.color));
    this.line = new Line(this.canvas, {
      from: new Point(this.point1.x + this.position.x, this.point1.y + this.position.y),
      to: new Point(this.point2.x + this.position.x, this.point2.y + this.position.y)
    });
    this.line.setColor(new Color(this.color));
    this.addChild(this.line, this.circle1, this.circle2, this.circle3);
    this.circle1.addEventListener(this.version === OChart.VERSION.PC ? Event.EVENT_MOUSE_MOVE : Event.EVENT_TOUCH_MOVE,(e) => {
      this.point1.x = e.curPoint.x;
      this.point1.y = e.curPoint.y;
      this.circle1.setPosition(this.point1.x + this.position.x, this.point1.y + this.position.y);
      this.circle3.setPosition(
        (this.point1.x + this.point2.x) / 2 + this.position.x,
        (this.point1.y + this.point2.y) / 2 + this.position.y
        );
      this.line.setFrom(this.point1.x + this.position.x, this.point1.y + this.position.y);
      this.canvas.paint();
      this.onLineMove && this.onLineMove({
        line: this,
        point1: this.point1,
        point2: this.point2
      });
      this.hasChange = true;
    });
    this.circle2.addEventListener(this.version === OChart.VERSION.PC ? Event.EVENT_MOUSE_MOVE : Event.EVENT_TOUCH_MOVE, (e) => {
      this.point2.x = e.curPoint.x;
      this.point2.y = e.curPoint.y;
      this.circle2.setPosition(this.point2.x + this.position.x, this.point2.y + this.position.y);
      this.circle3.setPosition(
        (this.point1.x + this.point2.x) / 2 + this.position.x,
        (this.point1.y + this.point2.y) / 2 + this.position.y
      );
      this.line.setTo(this.point2.x + this.position.x, this.point2.y + this.position.y);
      this.canvas.paint();
      this.onLineMove && this.onLineMove({
        line: this,
        point1: this.point1,
        point2: this.point2
      });
      this.hasChange = true;
    });
    this.circle3.addEventListener(this.version === OChart.VERSION.PC ? Event.EVENT_MOUSE_MOVE : Event.EVENT_TOUCH_MOVE, (e) => {
      const deltaX = e.curPoint.x - e.eventPoint.x;
      const deltaY = e.curPoint.y - e.eventPoint.y;
      this.point1.x += deltaX;
      this.point2.x += deltaX;
      this.point1.y += deltaY;
      this.point2.y += deltaY;
      this.circle1.setPosition(this.point1.x + this.position.x, this.point1.y + this.position.y);
      this.circle2.setPosition(this.point2.x + this.position.x, this.point2.y + this.position.y);
      this.circle3.setPosition(
        (this.circle1.x + this.circle2.x) / 2,
        (this.circle1.y + this.circle2.y) / 2
      );
      this.line.setFrom(this.circle1.x, this.circle1.y);
      this.line.setTo(this.circle2.x, this.circle2.y);
      this.onLineMove && this.onLineMove({
        line: this,
        point1: this.point1,
        point2: this.point2
      });
      this.hasChange = true;
    });
    this.addEventListener(this.version === OChart.VERSION.PC ? Event.EVENT_MOUSE_UP : Event.EVENT_TOUCH_END, () => {
      if (this.hasChange) {
        this.onLineMoved && this.onLineMoved(this);
      }
      this.hasChange = false;
    })
  }
  setSelected(isSelected) {
    this.circle1.visible = isSelected;
    this.circle2.visible = isSelected;
    this.circle3.visible = isSelected;
  }
  containsPoint (point) {
    let k = (this.point1.y - this.point2.y) / (this.point1.x - this.point2.x);
    let yDown = k * (point.x - this.point2.x) + this.point2.y - 10;
    let yUp = yDown + 20;
    if ((point.x - this.point1.x) * (point.x - this.point2.x) < 0 && (point.y - yDown) * (point.y - yUp) < 0) {
      return true;
    }
    return false;
  }
}

/**
 * 直线
 */
class StraightLayer extends Layer{
  constructor(canvas, options) {
    super(canvas);
    this.uuid = options.uuid;
    this.width = options.width;
    this.height = options.height;
    this.point1 = options.point1;
    this.point2 = options.point2;
    this.onLineMove = options.onLineMove;
    this.onLineMoved = options.onLineMoved;
    this.color = options.color || '#333333';
    this.version = options.version || OChart.VERSION.PC;
    this.hasChange = false;
    const k = (this.point1.x - this.point2.x) / (this.point1.y - this.point2.y);
    const zeroX = this.position.x + k * (this.position.y - this.point1.y) + this.point1.x;
    const topX = this.position.x + k * (this.position.y + this.height - this.point1.y) + this.point1.x;
    this.line = new Line(this.canvas, {
      from: new Point(zeroX, this.position.y),
      to: new Point(topX, this.position.y + this.height)
    });
    this.line.setColor(new Color(this.color));
    if (this.point1.x < this.position.x
      || this.point1.x > this.position.x + this.width
      || this.point1.y < this.position.y
      || this.point1.y > this.position.y + this.height) {
      this.point1.x = zeroX;
      this.point1.y = this.position.y;
    }

    if (this.point2.x < this.position.x
      || this.point2.x > this.position.x + this.width
      || this.point2.y < this.position.y
      || this.point2.y > this.position.y + this.height) {
      this.point2.x = topX;
      this.point2.y = this.position.y + this.height;
    }
    this.circle1 = new Circle(this.canvas, 10);
    this.circle2 = new Circle(this.canvas, 10);
    this.circle3 = new Circle(this.canvas, 10);
    this.circle1.setPosition(this.point1.x, this.point1.y);
    this.circle2.setPosition(this.point2.x, this.point2.y);
    this.circle3.setPosition(
      (this.point1.x + this.point2.x) / 2,
      (this.point1.y + this.point2.y) / 2
    );
    this.circle1.setColor(new Color(this.color));
    this.circle2.setColor(new Color(this.color));
    this.circle3.setColor(new Color(this.color));
    this.addChild(this.line, this.circle1, this.circle2, this.circle3);
    this.circle1.addEventListener(this.version === OChart.VERSION.PC ? Event.EVENT_MOUSE_MOVE : Event.EVENT_TOUCH_MOVE, (e) => {
      this.point1.x = e.curPoint.x;
      this.point1.y = e.curPoint.y;
      this.circle1.setPosition(this.point1.x, this.point1.y);
      this.circle3.setPosition(
        (this.point1.x + this.point2.x) / 2,
        (this.point1.y + this.point2.y) / 2
      );
      const k = (this.point1.x - this.point2.x) / (this.point1.y - this.point2.y);
      const zeroX = this.position.x + k * (this.position.y - this.point1.y) + this.point1.x;
      const topX = this.position.x + k * (this.position.y + this.height - this.point1.y) + this.point1.x;
      this.line.setFrom(zeroX, this.position.y);
      this.line.setTo(topX, this.position.y + this.height);
      this.canvas.paint();
      this.onLineMove && this.onLineMove({
        line: this,
        point1: this.point1,
        point2: this.point2
      });
      this.hasChange = true;
    });
    this.circle2.addEventListener(this.version === OChart.VERSION.PC ? Event.EVENT_MOUSE_MOVE : Event.EVENT_TOUCH_MOVE, (e) => {
      this.point2.x = e.curPoint.x;
      this.point2.y = e.curPoint.y;
      this.circle2.setPosition(this.point2.x, this.point2.y);
      this.circle3.setPosition(
        (this.point1.x + this.point2.x) / 2,
        (this.point1.y + this.point2.y) / 2
      );
      const k = (this.point1.x - this.point2.x) / (this.point1.y - this.point2.y);
      const zeroX = this.position.x + k * (this.position.y - this.point1.y) + this.point1.x;
      const topX = this.position.x + k * (this.position.y + this.height - this.point1.y) + this.point1.x;
      this.line.setFrom(zeroX, this.position.y);
      this.line.setTo(topX, this.position.y + this.height);
      this.canvas.paint();
      this.onLineMove && this.onLineMove({
        line: this,
        point1: this.point1,
        point2: this.point2
      });
      this.hasChange = true;
    });
    this.circle3.addEventListener(this.version === OChart.VERSION.PC ? Event.EVENT_MOUSE_MOVE : Event.EVENT_TOUCH_MOVE, (e) => {
      const deltaX = e.curPoint.x - e.eventPoint.x;
      const deltaY = e.curPoint.y - e.eventPoint.y;
      this.point1.x += deltaX;
      this.point2.x += deltaX;
      this.point1.y += deltaY;
      this.point2.y += deltaY;
      this.circle1.setPosition(this.point1.x, this.point1.y);
      this.circle2.setPosition(this.point2.x, this.point2.y);
      this.circle3.setPosition(
        (this.point1.x + this.point2.x) / 2,
        (this.point1.y + this.point2.y) / 2
      );
      const k = (this.point1.x - this.point2.x) / (this.point1.y - this.point2.y);
      const zeroX = this.position.x + k * (this.position.y - this.point1.y) + this.point1.x;
      const topX = this.position.x + k * (this.position.y + this.height - this.point1.y) + this.point1.x;
      this.line.setFrom(zeroX, this.position.y);
      this.line.setTo(topX, this.position.y + this.height);
      this.canvas.paint();
      this.onLineMove && this.onLineMove({
        line: this,
        point1: this.point1,
        point2: this.point2
      });
      this.hasChange = true;
    });
    this.addEventListener(this.version === OChart.VERSION.PC ? Event.EVENT_MOUSE_UP : Event.EVENT_TOUCH_END, () => {
      if (this.hasChange) {
        this.onLineMoved && this.onLineMoved(this);
      }
      this.hasChange = false;
    });
  }

  setSelected(isSelected) {
    this.circle1.visible = isSelected;
    this.circle2.visible = isSelected;
    this.circle3.visible = isSelected;
  }

  make(point1, point2) {
    this.point1.x = point1.x;
    this.point1.y = point1.y;
    this.point2.x = point2.x;
    this.point2.y = point2.y;
    this.circle1.setPosition(this.point1.x, this.point1.y);
    this.circle2.setPosition(this.point2.x, this.point2.y);
    this.circle3.setPosition((this.point1.x + this.point2.x) / 2, (this.point1.y + this.point2.y) / 2);
    const k = (this.point1.x - this.point2.x) / (this.point1.y - this.point2.y);
    const zeroX = this.position.x + k * (this.position.y - this.point1.y) + this.point1.x;
    const topX = this.position.x + k * (this.position.y + this.height - this.point1.y) + this.point1.x;
    this.line.setFrom(zeroX, this.position.y);
    this.line.setTo(topX, this.position.y + this.height);
  }

  containsPoint (point) {
    let k = (this.point1.y - this.point2.y) / (this.point1.x - this.point2.x);
    let yDown = k * (point.x - this.point2.x) + this.point2.y - 10;
    const zeroX = this.position.x +  (this.position.y - this.point1.y) / k + this.point1.x;
    const topX = this.position.x + (this.position.y + this.height - this.point1.y) / k + this.point1.x;
    let yUp = yDown + 20;
    if ((point.x - zeroX) * (point.x - topX) < 0 && (point.y - yDown) * (point.y - yUp) < 0) {
      return true;
    }
    return false;
  }
}

class MesureLinesLayer extends Layer {
  constructor(canvas, option) {
    super(canvas);
    this.mesures = option.mesures || [];
    this.position = option.position;
    // 保证point1位于point2之上
    this.point1 = option.point1.y > option.point2.y ? option.point1 : option.point2;
    this.point2 = option.point1.y > option.point2.y ? option.point2 : option.point1;
    this.width = option.width;
    this.color = option.color || '#333333';
    for (let i = 0; i < this.mesures.length; i++) {
      const rate = this.mesures[i] / 100;
      const x = this.point1.x * (1 - rate) + this.point2.x * rate + this.position.x;
      const y = this.point1.y * (1 - rate) + this.point2.y * rate + this.position.y;
      const line = new Line(this.canvas, {
        from: new Point(x, y),
        to: new Point(this.width, y)
      });
      line.setColor(new Color(this.color));
      const text = new Text(this.canvas, {
        text: this.mesures[i],
        font: 'PingFang SC',
        size: 24,
        color: this.color
      });
      text.setPosition(x, y);
      this.addChild(line, text);
    }
  }

  make(point1, point2) {
    this.point1 = point1.y > point2.y  ? point1 : point2;
    this.point2 = point1.y > point2.y ? point2 : point1;
    this.childs.splice(0, this.childs.length);
    for (let i = 0; i < this.mesures.length; i++) {
      const rate = this.mesures[i] / 100;
      const x = this.point1.x * (1 - rate) + this.point2.x * rate + this.position.x;
      const y = this.point1.y * (1 - rate) + this.point2.y * rate + this.position.y;
      const line = new Line(this.canvas, {
        from: new Point(x + this.position.x, y + this.position.y),
        to: new Point(this.width + this.position.x, y + this.position.y)
      });
      line.setColor(new Color(this.color));
      const text = new Text(this.canvas, {
        text: this.mesures[i],
        font: 'PingFang SC',
        size: 24,
        color: this.color
      });
      text.setPosition(x + this.position.x, y + this.position.y);
      this.addChild(line, text);
    }
  }
}
/**
 * 比例线
 */
class RuleLayer extends Layer {
  constructor(canvas, options) {
    super(canvas);
    this.uuid = options.uuid;
    this.width = options.width;
    this.height = options.height;
    this.point1 = options.point1;
    this.point2 = options.point2;
    this.mesures = options.mesures || [];
    this.onLineMove = options.onLineMove;
    this.onLineMoved = options.onLineMoved;
    this.version = options.version || OChart.VERSION.PC;
    this.color = options.color || '#333333';
    this.hasChange = false;
    this.line = new Line(this.canvas, {
      from: new Point(this.point1.x, this.point1.y ),
      to: new Point(this.point2.x, this.point2.y)
    });
    this.line.setColor(new Color(this.color));
    this.circle1 = new Circle(this.canvas, 10);
    this.circle2 = new Circle(this.canvas, 10);
    this.circle3 = new Circle(this.canvas, 10);
    this.circle1.setPosition(this.point1.x + this.position.x, this.point1.y + this.position.y);
    this.circle2.setPosition(this.point2.x + this.position.x, this.point2.y + this.position.y);
    this.circle3.setPosition(
      (this.point1.x + this.point2.x) / 2,
      (this.point1.y + this.point2.y) / 2
    );
    this.circle1.setColor(new Color(this.color));
    this.circle2.setColor(new Color(this.color));
    this.circle3.setColor(new Color(this.color));
    this.mesureLayer = new MesureLinesLayer(this.canvas, {
      width: this.width,
      mesures: this.mesures,
      point1: this.point1,
      point2: this.point2,
      color: this.color,
      position: this.position,
    });
    this.addChild(this.line, this.circle1, this.circle3, this.circle2, this.mesureLayer);
    this.circle1.addEventListener(this.version === OChart.VERSION.PC ? Event.EVENT_MOUSE_MOVE : Event.EVENT_TOUCH_MOVE, (e) => {
      this.point1.x = e.curPoint.x;
      this.point1.y = e.curPoint.y;
      this.circle1.setPosition(this.point1.x + this.position.x, this.point1.y + this.position.y);
      this.circle3.setPosition(
        (this.point1.x + this.point2.x) / 2,
        (this.point1.y + this.point2.y) / 2
      );
      this.line.setFrom(this.point1.x, this.point1.y);
      this.mesureLayer.setPosition(this.position);
      this.mesureLayer.make(this.point1, this.point2);

      this.canvas.paint();
      this.onLineMove && this.onLineMove({
        line: this,
        point1: this.point1,
        point2: this.point2
      });
      this.hasChange = true;
    });

    this.circle2.addEventListener(this.version === OChart.VERSION.PC ? Event.EVENT_MOUSE_MOVE : Event.EVENT_TOUCH_MOVE, (e) => {
      this.point2.x = e.curPoint.x;
      this.point2.y = e.curPoint.y;
      this.circle2.setPosition(this.point2.x + this.position.x, this.point2.y + this.position.y);
      this.circle3.setPosition(
        (this.point1.x + this.point2.x) / 2,
        (this.point1.y + this.point2.y) / 2
      );
      this.line.setTo(this.point2.x, this.point2.y);
      this.mesureLayer.setPosition(this.position);
      this.mesureLayer.make(this.point1, this.point2);
      this.canvas.paint();
      this.onLineMove && this.onLineMove({
        line: this,
        point1: this.point1,
        point2: this.point2
      });
      this.hasChange = true;
    });
    this.circle3.addEventListener(this.version === OChart.VERSION.PC ? Event.EVENT_MOUSE_MOVE : Event.EVENT_TOUCH_MOVE, (e) => {
      const deltaX = e.curPoint.x - e.eventPoint.x;
      const deltaY = e.curPoint.y - e.eventPoint.y;
      this.point1.x += deltaX;
      this.point2.x += deltaX;
      this.point1.y += deltaY;
      this.point2.y += deltaY;
      this.circle1.setPosition(this.point1.x + this.position.x, this.point1.y + this.position.y);
      this.circle2.setPosition(this.point2.x + this.position.x, this.point2.y + this.position.y);
      this.circle3.setPosition(
        (this.point1.x + this.point2.x) / 2,
        (this.point1.y + this.point2.y) / 2
      );
      this.line.setFrom(this.point1.x, this.point1.y);
      this.line.setTo(this.point2.x, this.point2.y);
      this.mesureLayer.setPosition(this.position);
      this.mesureLayer.make(this.point1, this.point2);
      this.canvas.paint();
      this.onLineMove && this.onLineMove({
        line: this,
        point1: this.point1,
        point2: this.point2
      });
      this.hasChange = true;
    });
    this.addEventListener(this.version === OChart.VERSION.PC ? Event.EVENT_MOUSE_UP : Event.EVENT_TOUCH_END, (e) => {
      if (this.hasChange) {
        this.onLineMoved && this.onLineMoved(this);
      }
      this.hasChange = false;
    })
  }
  setSelected(isSelected) {
    this.circle1.visible = isSelected;
    this.circle2.visible = isSelected;
    this.circle3.visible = isSelected;
  }
  containsPoint (point) {
    let k = (this.point1.y - this.point2.y) / (this.point1.x - this.point2.x);
    let yDown = k * (point.x - this.point2.x) + this.point2.y - 10;
    let yUp = yDown + 20;
    if ((point.x - this.point1.x) * (point.x - this.point2.x) < 0 && (point.y - yDown) * (point.y - yUp) < 0) {
      return true;
    }
    return false;
  }
}

/**
 * 分段框
 */
class SeparatorLayer extends Layer {

}
